# Script used to compute mean of images
#####################################

#setwd("C:/Users/Jerry/Documents/CSE 446/project/images")
library(pixmap)

# returns a vector representing the pixels stored in file "fileName"
# (collapsed row-major-wise from the pixel matrix)
# Requires: the pgm maxVal occurs on the third line of the image file
getVector <- function(fileName) {
  # read in the images as pnm format (see ?pixmap)
  cur_pixmap = read.pnm(fileName)
  
  # read in the maxVal for this image
  # TODO: improve this so that we don't always look for maxVal in the third line
  cur_maxVal = scan(fileName, skip=2, nlines=1)
  
  # a matrix of the greyscale values of this image
  # note that getChannels normalizes every geryscale value to the interval [0,1]
  # hence the need to reconstitute the original matrix by multiplying by cur_maxVal    
  cur_matrix = cur_maxVal * getChannels(cur_pixmap)
  
  # collapse the matrix into a vector (row-major order)
  return(as.vector(t(cur_matrix)))
}

# Returns a two-element list
# the first element of the list is an N by M matrix consisting of mean-centered column vectors;
#   each column vector corresponds to an image in the list "fileNames"
# the second element of the list is an N by 1 mean vector
# N is the number of pixels in each image
# M is the number of images contained in fileNames
# Params: 
#   fileNames - a non-empty vector of image file names (represented as strings)
# Requires: All images have the same width and height; the pgm maxVal occurs on the third line of the image file
get_mean_centered_matrix <- function(fileNames){
  # the total number of files
  M = length(fileNames)
  
  # the width-height dimension of the images
  mat_dim = read.pnm(fileNames[1])@size
  
  # the total number of pixels in each image (=N in the spec)
  pix_num = mat_dim[1] * mat_dim[2]
  
  # the vector used to store the sum of all the image vectors (initialized to zeros)
  sum_vec = rep(0, pix_num)
  
  # a matrix with pix_num rows that will be used to stack up all mean-centered images as column vectors
  original_images = matrix(numeric(0), pix_num, 0)
  
  for (fileName in fileNames){
    print(sprintf("reading in %s...", fileName))
    
    cur_vec = getVector(fileName)
    
    # bind the vector (as a column) to the original_images matrix
    original_images = cbind(original_images, cur_vec)
    
    # accumulate vector
    sum_vec = sum_vec + cur_vec
  }
  
  # the mean vector of all the images
  mean_vec = sum_vec / M
  
  # finally... mean-center the images
  mean_centered = original_images - mean_vec
  
  # round the entries to nearest integer
  return (list((round(mean_centered)), round(mean_vec), original_images))
}

############
# Quick test
############
#jerry_list = c("1.pgm", "2.pgm", "3.pgm")
#testFiles = c("./faces/an2i/an2i_left_angry_open_4.pgm", "./faces/an2i/an2i_up_sad_sunglasses_4.pgm")
#M = get_mean_centered_matrix(testFiles)[[1]]
#mean = get_mean_centered_matrix(testFiles)[[2]]

#pixmap1 = read.pnm("an2i_left_angry_open_4.pgm")
#pixmap2 = read.pnm("an2i_up_sad_sunglasses_4.pgm")
#maxVal1 = scan("an2i_left_angry_open_4.pgm", skip=2, nlines=1)
#maxVal2 = scan("an2i_up_sad_sunglasses_4.pgm", skip=2, nlines=1)
#M1 = maxVal1 * getChannels(pixmap1)
#M2 = maxVal2 * getChannels(pixmap2)
